package com.innjia.base.exception;

import com.innjia.base.utils.JsonUtil;
import com.innjia.base.utils.Result;
import com.innjia.base.utils.WebUtils;
import org.apache.shiro.authz.UnauthorizedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;

/**
 * 类的功能描述.
 * 自定义异常
 * 用于处理在请求映射和请求处理过程中抛出的异常的类，都要实现HandlerExceptionResolver接口。
 * HandlerExceptionResolver接口有一个方法resolveException，当controller层出现异常之后就会进入到这个方法resolveException
 * @auther innjia
 * @Date 2017/7/21
 */

public class MyHandlerExceptionResoler implements HandlerExceptionResolver {
    private static final Logger LOGGER = LoggerFactory.getLogger(MyHandlerExceptionResoler.class);

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object o, Exception e) {
        //如果请求是ajax 返回json格式
        if (WebUtils.isAjax(request) || isHandlerMethodForAjax(o)) {
            try {
                response.setContentType("application/json;charset=UTF-8");
                PrintWriter writer = response.getWriter();
                //为了系统安全,只让用户看自定义异常错误信息
                if(e instanceof MyException){
                    LOGGER.error("一个ajax请求，发生业务错误", e);
                    Result error = Result.error(e.getMessage());
                    writer.write(JsonUtil.getJsonByObj(error));
                }else if (e instanceof UnauthorizedException){
                    LOGGER.info("一个ajax请求，发生系统错误", e);
                    Result error = Result.error("对不起，没有权限操作!");
                    writer.write(JsonUtil.getJsonByObj(error));
                } else {
                    LOGGER.error("一个ajax请求，发生系统错误", e);
                    Result error = Result.error("系统异常,请联系技术人员!");
                    writer.write(JsonUtil.getJsonByObj(error));
                }

                writer.flush();
                writer.close();
            } catch (IOException e1) {
                LOGGER.error("", e1);
            }
        } else {
            // 如果不是ajax，JSP格式返回
            Result result = null;
            if(e instanceof MyException){
                LOGGER.error("一个非ajax请求，发生业务错误", e);
                result = Result.error(e.getMessage());
            }else if (e instanceof UnauthorizedException){
                LOGGER.error("一个ajax请求，发生系统错误:", e);
                result = Result.error("对不起，没有权限操作!");
            } else {
                LOGGER.error("一个非ajax请求，发生系统错误", e);
                result = Result.error("系统异常,请联系技术人员!");
            }
            return new ModelAndView("error.jsp",result);
        }

        return null;
    }

    /*
     * 判断是否是 ajax 请求
     * 1. 返回类型是 void
     * 2. 使用了 ResponseBody 注解
     */
    private boolean isHandlerMethodForAjax(Object methodObject){
        if(methodObject == null || !(methodObject instanceof HandlerMethod))
            return false;

        HandlerMethod handlerMethod = (HandlerMethod) methodObject;
        Method method = handlerMethod.getMethod();

        //返回类型是 void 的
        @SuppressWarnings("rawtypes")
        Class returnType = method.getReturnType();
        if(returnType != null && "void".equals(returnType.getName())){
            return true;
        }

        //是否使用了 ResponseBody 注解
        ResponseBody responseBodyAnn
                = AnnotationUtils.findAnnotation(method, ResponseBody.class);
        if(responseBodyAnn == null){
            // 判断 contrller 上是否使用了@ReponseBody 注解
            responseBodyAnn
                    = AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), ResponseBody.class);
        }

        return responseBodyAnn != null;

    }
}
